#include <TGS/GeoMath2.0/Vector.h>
#include <TGS/GeoMath2.0/Point.h>
#include <TGS/GeoMath2.0/Angle.h>
#include <cmath>
#include <limits>

namespace
{
	const double PI = 3.14159265358979323846;
}

namespace TGS{
namespace GeoMath{

Vector::Vector()
{

}

Vector::Vector(double x, double y)
	: _x(x)
	, _y(y)
{

}

Vector::Vector( const Point& startPoint, const Point& endPoint )
	: _x(endPoint.getX() - startPoint.getX())
	, _y(endPoint.getY() - startPoint.getY())
{

}

//////////////////////////////////////////////////////////////////////////

inline double Vector::getX() const
{
	return _x;
}

inline double Vector::getY() const
{
	return _y;
}

inline void Vector::setX(double x)
{
	_x = x;
}

inline void Vector::setY(double y)
{
	_y = y;
}

//////////////////////////////////////////////////////////////////////////

inline double Vector::magnitude() const
{
	double magnitude_sqr = _x * _x + _y * _y;

	return std::sqrt(magnitude_sqr);
}

inline void Vector::normalize()
{
	double mag = magnitude();
	if(mag != 0)
	{
		_x /= mag;
		_y /= mag;
	}
	else
	{
		const double MAX = std::numeric_limits<double>::max();
		_x = _y = MAX;
	}
}

//////////////////////////////////////////////////////////////////////////

double Vector::Dot(const Vector& lhs, const Vector& rhs)
{
	return 
		lhs.getX() * rhs.getX() +
		lhs.getY() * rhs.getY();
}

double Vector::Cross(const Vector& lhs, const Vector& rhs)
{
	return 
		lhs.getX() * rhs.getY() -
		lhs.getY() * rhs.getX();
}

Angle Vector::Angle(const Vector& lhs, const Vector& rhs)
{
	double cosA = Vector::Dot(lhs, rhs) / (lhs.magnitude() * rhs.magnitude());

	return Angle::fromRadian(std::acos(cosA));
}

Angle Vector::angle() const
{
	double ang = atan2( _y, _x );
	return Angle::fromRadian(ang < 0.0 ? ang + 2.0 * PI : ang);
}

TGS::GeoMath::Vector operator-( const Point& lhs, const Point& rhs )
{
	return Vector(lhs.getX() - rhs.getX(), lhs.getY() - rhs.getY());
}

}
}